| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128 |
- ;
- ; Command & Conquer Red Alert(tm)
- ; Copyright 2025 Electronic Arts Inc.
- ;
- ; This program 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.
- ;
- ; This program is distributed in the hope that it will be useful,
- ; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ; GNU General Public License for more details.
- ;
- ; You should have received a copy of the GNU General Public License
- ; along with this program. If not, see <http://www.gnu.org/licenses/>.
- ;
- ;***************************************************************************
- ;** 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 : WWLIB32 *
- ;* *
- ;* File Name : DRAWSHP.ASM *
- ;* *
- ;* Programmer : Phil W. Gorrow *
- ;* *
- ;* Start Date : April 13, 1992 *
- ;* *
- ;* Last Update : September 14, 1994 [IML] *
- ;* *
- ;*-------------------------------------------------------------------------*
- ;* Functions: *
- ;* Draw_Shape -- Draws a shape at given buffer coordinates and clips *
- ;* Not_Supported -- Replacement function for Draw_Shape routines not used*
- ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
- ;********************* Model & Processor Directives ************************
- IDEAL
- P386
- MODEL USE32 FLAT
- ; this struct is here to remove the hardwire way of programing
- ; implemented in the funtion Draw_Shape in ian image of
- STRUC VVPC_IMAGE
- Off dd ?
- Width dd ?
- Height dd ?
- Page dd ?
- ENDS
- STRUC GVPC_IMAGE
- vvpc VVPC_IMAGE <>
- Xpos dd ?
- Ypos dd ?
- GraphicBuff dd ?
- ENDS
- ;******************************** Includes *********************************
- INCLUDE "shape.inc"
- ;****************************** Declarations ********************************
- GLOBAL Draw_Shape:NEAR
- GLOBAL LCW_Uncompress:NEAR
- GLOBAL _ShapeBuffer:DWORD
- GLOBAL _ShapeBufferSize:DWORD
- GLOBAL MaskPage : dword
- GLOBAL BackGroundPage : dword
- ;********************************* Data ************************************
- DATASEG
- ;---------------------------------------------------------------------------
- ; Shape buffer & its size, set by Set_Shape_Buffer()
- ;---------------------------------------------------------------------------
- _ShapeBuffer DD 0
- _ShapeBufferSize DD 0
- ;---------------------------------------------------------------------------
- ; Address of MaskPage & BackGroundPage, set by Init_Priority_System()
- ;---------------------------------------------------------------------------
- MaskPage DD 0
- BackGroundPage DD 0
- ;---------------------------------------------------------------------------
- ; Predator effect variables
- ;---------------------------------------------------------------------------
- PredCount DD 0
- PredTable DB 1, 3, 2, 5, 4, 3, 2, 1
- PredValue DD 1
- PartialPred DD 0 ; partially faded predator effect value
- PartialCount DD 0
- ;---------------------------------------------------------------------------
- ; 32 bit versions of 16 bit stack variables
- ;---------------------------------------------------------------------------
- Flags DD ? ; globally accessible copy of flags
- viewport_ptr DD ? ; pointer to upper-left corner of viewport
- viewport_width DD ? ; viewport width
- viewport_height DD ? ; viewport height
- viewport_yadd DD ? ; viewport y add
- viewport_x DD ? ; viewport x-coord
- viewport_y DD ? ; viewport y-coord
- buff_ptr DD ? ; pointer to buffer containing viewport
- ;********************************* Code ************************************
- CODESEG
- ;***************************************************************************
- ;* Draw_Shape -- Draws a shape at given buffer coordinates and clips *
- ;* *
- ;* INPUT: *
- ;* DWORD gvp_ptr ; pointer to graphic viewport info *
- ;* DWORD shape_ptr ; the shape pointer to draw *
- ;* DWORD draw_x ; x-coord of hotspot in viewport *
- ;* DWORD draw_y ; y-coord of hotspot in viewport *
- ;* DWORD flags ; the flags for drawing the shape *
- ;* *
- ;* Optional Arguments: If the following flags are used, the given args *
- ;* MUST be present. Note that, if more than one one set of args is used, *
- ;* they must appear in this order (alphabetical). *
- ;* SHAPE_COLOR: DWORD color_table (256 bytes) *
- ;* SHAPE_FADING: DWORD fade_table (256 bytes), DWORD fade_count *
- ;* SHAPE_GHOST: DWORD is_translucent tbl, DWORD translucent tbl *
- ;* SHAPE_PARTIAL: DWORD predator partial_value (0-255) *
- ;* SHAPE_PRIORITY: DWORD priority_level *
- ;* SHAPE_SCALING: DWORD x_scale, WORD y_scale *
- ;* SHAPE_SHADOW: DWORD shadowing_table (256 bytes) *
- ;* *
- ;* OUTPUT: *
- ;* none. *
- ;* *
- ;* WARNINGS: *
- ;* none. *
- ;* *
- ;*-------------------------------------------------------------------------*
- ;* *
- ;* File Organization: *
- ;* drawshp.asm : this file *
- ;* shape.inc : main shape header file; contains declarations for all *
- ;* globals, procedures and constants *
- ;* ds_table.asm: contains the procedure address tables for LSkipRout, *
- ;* RSkipRout, DrawRout, & PixelRout *
- ;* ds_l*.asm : left-skip routines *
- ;* ds_r*.asm : right-skip routines *
- ;* ds_d*.asm : drawing routines *
- ;* *
- ;*-------------------------------------------------------------------------*
- ;* *
- ;* Shape format: *
- ;* Header: *
- ;* UWORD SType (0=normal, 1=16-color, 2=uncompressed, 4=variable-color) *
- ;* UBYTE Height *
- ;* UWORD Width *
- ;* UBYTE unmodified height *
- ;* UWORD size of shape in memory, including this header *
- ;* UWORD uncompressed data size *
- ;* Normal Shape: *
- ;* UBYTE [compressed] Shape data *
- ;* 16-color shape: *
- ;* UBYTE 16-color table *
- ;* UBYTE [compressed] Shape data *
- ;* variable-color shape: *
- ;* UBYTE # colors *
- ;* UBYTE color table (variable-length) *
- ;* UBYTE [compressed] Shape data *
- ;* *
- ;*-------------------------------------------------------------------------*
- ;* *
- ;* Uncompressed shape data format: *
- ;* Data is stored as a bitmap, with 0's treated as a special case. Every *
- ;* 0 byte is followed by a repetition count byte. Every scan line is *
- ;* compressed separately. Thus, the following bitmap results in the *
- ;* following shape data: *
- ;* 0 0 0 5 6 7 0 0 0 0 *
- ;* 0 0 0 5 6 7 0 0 0 0 *
- ;* 0 0 0 5 6 7 0 0 0 0 *
- ;* *
- ;* 0 3 5 6 7 0 4 *
- ;* 0 3 5 6 7 0 4 *
- ;* 0 3 5 6 7 0 4 *
- ;* *
- ;*-------------------------------------------------------------------------*
- ;* *
- ;* How scaling is handled: *
- ;* Scaling is done by accumulating the x & y scale values. When the high *
- ;* byte of the accumulated value is set, the pixel (for x-scaling) or *
- ;* the line (for y-scaling) is drawn. The high byte is then cleared, *
- ;* and the low byte is left so roundoffs continue to accumulate. *
- ;* *
- ;*-------------------------------------------------------------------------*
- ;* *
- ;* Drawing Procedures: *
- ;* *
- ;*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*
- ;* *
- ;* RSkipRout: skips given # bytes of data on the right-hand side of a *
- ;* shape. Just has to handle changing the current byte offset in the *
- ;* shape data buffer, since the draw routine knows where the left-hand *
- ;* side of the drawable region is. The routine may skip more bytes than *
- ;* it was told if it encounters a run of 0's, but it's assumed that a *
- ;* run of 0's will never go past the right edge of a shape. *
- ;* Input: *
- ;* ECX - number of uncompressed bytes to skip *
- ;* ESI - shape buffer data address *
- ;* Output: *
- ;* ECX - negative # bytes overrun, or 0 *
- ;* ESI - updated to the current location in the shape data *
- ;* *
- ;*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*
- ;* *
- ;* LSkipRout: skips given # bytes of data on the left-hand side of a *
- ;* shape. This routine must update the shape data byte offset, and it *
- ;* must properly update the current drawing position due to scaling, so *
- ;* it's a little more involved than the RSkip routine. The routine may *
- ;* skip more bytes than it's told if it encounters a run of 0's. If this *
- ;* happens, the draw routine must take these extra bytes into *
- ;* consideration. *
- ;* Input: *
- ;* ECX = number of uncompressed bytes to skip *
- ;* ESI = shape (source) buffer data address *
- ;* EDI = viewport (destination) address *
- ;* [WidthCount] = shape's width in bytes *
- ;* Output: *
- ;* ECX - negative # pixels (not bytes) overrun, or 0 *
- ;* EDX - accumulated XTotal value at new pixel location *
- ;* ESI - updated to the current location in the shape data *
- ;* EDI - incr/decr by # pixels (not bytes) overrun *
- ;* [WidthCount] - decremented by # bytes skipped *
- ;* *
- ;*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*
- ;* *
- ;* DrawRout: draws one row of pixels, handles scaling, reversal and *
- ;* any per pixel effects like predator, shadow etc. *
- ;* EDX must be set up as follows: *
- ;* - No scaling: 0 *
- ;* - No left-clipping: 0 *
- ;* - Left clipping, but no overrun: set to computed initial value for *
- ;* that viewport coordinate *
- ;* - Left clipping, with overrun: set to XTotal value for that coordinate *
- ;* In any case, only the low byte of DL should contain data; the current *
- ;* byte in the shapebuffer should always be the first drawable pixel, *
- ;* even if it's partially clipped (in which case DL will contain data). *
- ;* Input: *
- ;* ECX = number of pixels (not bytes) to draw *
- ;* EDX = XTotal initializer value *
- ;* ESI = shape (source) buffer address *
- ;* EDI = viewport (destination) address *
- ;* [WidthCount] = remaining bytes on the line *
- ;* Output: *
- ;* ESI - updated to current location in the shape data *
- ;* EDI - incr/decr by # pixels (not bytes) drawn/skipped *
- ;* [WidthCount] - decremented by # bytes (not pixels) drawn *
- ;* *
- ;*-------------------------------------------------------------------------*
- ;* *
- ;* Algorithm: *
- ;* - Initialize globals *
- ;* - Pull optional arguments off the stack *
- ;* - Set up drawing procedure pointers based on drawing flags *
- ;* - Read the values from the shape header *
- ;* - Compute the shape's scaled width & height *
- ;* - Adjust the shape's drawing coordinates based on centering & *
- ;* viewport-relative flag settings *
- ;* - Compute the clipped areas of the shape *
- ;* - Compute the number of drawn pixels horizontally & vertically *
- ;* - Compute the starting drawing offset in the viewport *
- ;* - Draw the shape *
- ;* *
- ;*-------------------------------------------------------------------------*
- ;* *
- ;* HISTORY: *
- ;* 04/13/1992 PWG : Created. *
- ;* 08/19/1993 SKB : Split drawshp.asm into several modules. *
- ;* 05/26/1994 BR : Converted to 32-bit, restructured quite a bit. *
- ;* 08/09/1994 IML : Added C++ style interface. Various optimizations. *
- ;* 09/06/1994 IML : Ammendments for integration of p_* and ds_* routines.*
- ;* 09/14/1994 IML : Now handles LCW compression. *
- ;*=========================================================================*
- PROC Draw_Shape C NEAR
- USES eax,ebx,ecx,edx,edi,esi
- ;--------------------------------------------------------------------
- ; Arguments:
- ;--------------------------------------------------------------------
- ARG gvp_ptr:DWORD ; pointer to graphic viewport info
- ARG shape_ptr:DWORD ; the shape pointer to draw
- ARG draw_x:DWORD ; the destination x pixel
- ARG draw_y:DWORD ; the destination y pixel
- ARG flags:DWORD ; the flags for drawing the shape
- IF FALSE
- ;--------------------------------------------------------------------
- ; Define the local stack variables that Draw_Shape needs. These
- ; parameters are defined in shape.inc. They're included here
- ; just for reference.
- ;--------------------------------------------------------------------
- ;
- ;...................... proc addresses ..............................
- ;
- LOCAL LSkipRout:DWORD ; pointer to the skip routine
- LOCAL RSkipRout:DWORD ; pointer to the skip routine
- LOCAL DrawRout:DWORD ; pointer to the draw routine
- ;
- ;.................... optional arguments ............................
- ;
- LOCAL ColorTable:DWORD ; ptr to the shapes color table
- LOCAL FadingTable:DWORD ; extracted fading table pointer
- LOCAL FadingNum:DWORD ; get the number of times to fade
- LOCAL IsTranslucent:DWORD ; ptr to "are we translucent?" tbl
- LOCAL Translucent:DWORD ; ptr to "ok we are translucent!" tbl
- LOCAL PriLevel:BYTE ; the priority level of the object
- LOCAL ScaleX:DWORD ; the x increment to scale by
- LOCAL ScaleY:DWORD ; the y increment to scale by
- LOCAL ShadowingTable:DWORD ; ptr to the shadowing table
- ;
- ;.................... Shape header values ...........................
- ;
- LOCAL ShapeType:DWORD ; shape type
- LOCAL ShapeWidth:DWORD ; shape's unscaled width
- LOCAL ShapeHeight:DWORD ; shape's unscaled height
- LOCAL UncompDataLen:DWORD ; uncompressed data length
- LOCAL ShapeData:DWORD ; pointer to [compressed] shape data
- ;
- ;.................. Scaled shape dimensions .........................
- ;
- LOCAL ScaledWidth:DWORD ; shape's scaled width
- LOCAL ScaledHeight:DWORD ; shape's scaled height
- ;
- ;.................. Pixel clipping variables ........................
- ;
- LOCAL LeftClipPixels:DWORD ; # left-clipped pixels
- LOCAL RightClipPixels:DWORD ; # right-clipped pixels
- LOCAL TopClipPixels:DWORD ; # top-clipped pixels
- LOCAL BotClipPixels:DWORD ; # bottom-clipped pixels
- LOCAL PixelWidth:DWORD ; width of drawable area in pixels
- LOCAL PixelHeight:DWORD ; height of drawable area in pixels
- ;
- ;..................... Drawing variables ............................
- ;
- LOCAL NumColors:DWORD ; # colors for 16-color shapes
- LOCAL StartDraw:DWORD ; ptr to starting draw position
- LOCAL NextLine:DWORD ; offset of next drawing line
- LOCAL LeftClipBytes:DWORD ; # left-clipped bytes
- LOCAL XTotal:DWORD ; accumulated x-pixels for scaling
- LOCAL XTotalInit:DWORD ; initial roundoff bits for XTotal
- LOCAL YTotal:DWORD ; accumulated y-pixels for scaling
- LOCAL HeightCount:DWORD ; height counter for drawing lines
- LOCAL LineStart:DWORD ; address of start of line
- LOCAL WidthCount:DWORD ; counts down # bytes skipped
- LOCAL StashReg:DWORD ; temp variable for draw routines
- LOCAL MaskAdjust:DWORD ; priority buffer offset
- LOCAL BackAdjust:DWORD ; background buffer offset
- LOCAL StashECX:DWORD ; temp variable for ECX register
- LOCAL StashEDX:DWORD ; temp variable for EDX register
- ENDIF
- ;====================================================================
- ; Initialization:
- ; - allocate space for globals
- ; - validate shape pointer
- ; - set SHAPE_COMPACT flag if needed
- ;====================================================================
- ;--------------------------------------------------------------------
- ; Allocate stack space for our local variables.
- ;--------------------------------------------------------------------
- LOCAL Local_Stack:BYTE:Local_Size
- ;--------------------------------------------------------------------
- ; Make sure the shape pointer is not NULL
- ;--------------------------------------------------------------------
- cmp [shape_ptr],0 ; compare shape ptr value to NULL
- jnz ??valid_shp ; if non-zero, it's valid
- jmp ??exit ; otherwise get the heck outta here
- ;--------------------------------------------------------------------
- ; Move gvp info into local variables
- ;--------------------------------------------------------------------
- ??valid_shp:
- mov edi,[gvp_ptr] ; get pointer to graphic viewport info
- mov esi, [(type GVPC_IMAGE ptr edi). vvpc . Off ] ; extract viewport pointer
- mov [viewport_ptr],esi
- mov ebx,[(type GVPC_IMAGE ptr edi) . vvpc . Width ] ; extract viewport width
- mov [viewport_width],ebx
- mov eax,[(type GVPC_IMAGE ptr edi) . vvpc . Height ] ; extract viewport height
- mov [viewport_height],eax
- mov ecx,[(type GVPC_IMAGE ptr edi) . vvpc . Page ] ; calculate y add value
- add ecx,ebx
- mov [viewport_yadd],ecx
- mov eax,[(type GVPC_IMAGE ptr edi) . Xpos ] ; extract viewport x-coord
- mov [viewport_x],eax
- mov eax, [(type GVPC_IMAGE ptr edi) . Ypos ] ; extract viewport y-coord
- mov [viewport_y],eax
- mul ecx ; calculate buffer pointer
- add eax,[viewport_x]
- sub esi,eax
- mov [buff_ptr],esi
- ;--------------------------------------------------------------------
- ; If this shape is a compact shape, set that bit in the flags arg
- ;--------------------------------------------------------------------
- mov edi,[shape_ptr] ; check for compact shape flag
- test [BYTE PTR edi],MAKESHAPE_COMPACT
-
- jz ??do_args ; if not process flags as is
- or [flags],SHAPE_COMPACT ; mark it as a compact shape
- ;====================================================================
- ; Pull off optional arguments:
- ; EDI is used as an offset from the 'flags' parameter, to point
- ; to the optional argument currently being processed.
- ;====================================================================
- ??do_args:
- mov edi,4 ; optional params start past flags
- ;--------------------------------------------------------------------
- ; Initialize optional argument values:
- ;--------------------------------------------------------------------
- mov [ColorTable],0 ; default = NULL
- mov [FadingTable],0 ; default = NULL
- mov [FadingNum],0 ; default = no fading
- mov [IsTranslucent],0 ; default = NULL
- mov [Translucent],0 ; default = NULL
- mov [PriLevel],0 ; default = no priority
- mov [ScaleX],100h ; default = unity X scaling
- mov [ScaleY],100h ; default = unity Y scaling
- mov [ShadowingTable],0 ; default = NULL
- ;--------------------------------------------------------------------
- ; SHAPE_COLOR: DWORD color_table[256]
- ;--------------------------------------------------------------------
- ??color:
- test [flags],SHAPE_COLOR ; does it have a color table
- jz ??fading ; if not skip to fading
- or [flags],SHAPE_COMPACT ; mark it as a compact shape
- ; (for remapping purposes only)
- mov eax,[flags + edi]
- mov [ColorTable],eax ; save address of color table
- add edi,4 ; point to next optional argument
- ;--------------------------------------------------------------------
- ; SHAPE_FADING: DWORD fade_table[256], DWORD fade_count
- ;--------------------------------------------------------------------
- ??fading:
- test [flags],SHAPE_FADING ; are we fading this shape
- jz ??ghost ; skip to ghosting check
- mov eax,[flags + edi]
- mov [FadingTable],eax ; save address of fading tbl
- mov eax,[flags + edi + 4] ; get fade num
- add edi,8 ; next argument
- cmp eax,0 ; check if it's 0
- jnz ??set_fading ; if not, store fade num
- and [flags],NOT SHAPE_FADING ; otherwise, don't fade
- ??set_fading:
- mov [FadingNum],eax
- ;--------------------------------------------------------------------
- ; SHAPE_GHOST: DWORD is_translucent tbl, DWORD translucent tbl
- ;--------------------------------------------------------------------
- ??ghost:
- test [flags],SHAPE_GHOST ; are we ghosting this shape
- jz ??init_predator ; skip to predator check
- mov eax,[flags + edi]
- mov [IsTranslucent],eax ; save ptr to is_trans. tbl
- mov eax,[flags + edi + 4]
- mov [Translucent],eax ; save ptr to translucent tbl
- add edi,8 ; next argument
- ;--------------------------------------------------------------------
- ; SHAPE_PREDATOR: Initialize the predator effect variables
- ;--------------------------------------------------------------------
- ??init_predator:
- test [flags],SHAPE_PREDATOR ; is predator effect on
- jz ??partial ; if not skip to partial
- inc [PredCount] ; the pred table is byte aligned
- and [PredCount],PRED_MASK ; keep entries within bounds
- mov eax,[PredCount]
- mov al,[BYTE PTR PredTable + eax]
- mov [PredValue],eax ; put the pred value cs
- mov [PartialCount],0 ; clear the partial count
- mov [PartialPred],100h ; init partial to off
- ;--------------------------------------------------------------------
- ; SHAPE_PARTIAL: DWORD partial_pred_value (0-255)
- ;--------------------------------------------------------------------
- ??partial:
- test [flags],SHAPE_PARTIAL ; is this a partial pred?
- jz ??priority ; if not check priority
- mov eax,[flags + edi] ; pull the partial value
- mov [PartialPred],eax ; store it off
- add edi,4 ; next argument
- ;--------------------------------------------------------------------
- ; SHAPE_PRIORITY: DWORD priority_level
- ;--------------------------------------------------------------------
- ??priority:
- test [flags],SHAPE_PRIORITY ; is this a priority draw
- jz ??scale ; if not skip to scale
- mov eax,[flags + edi]
- mov [PriLevel],al ; store priority level
- add edi,4 ; next argument
- mov eax,[MaskPage] ; calculate priority buffer
- sub eax,[buff_ptr] ; offset
- mov [MaskAdjust],eax
- mov eax,[BackGroundPage] ; calculate background buffer
- sub eax,[buff_ptr] ; offset
- mov [BackAdjust],eax
- ;--------------------------------------------------------------------
- ; SHAPE_SCALING: DWORD x_scale, WORD y_scale
- ;--------------------------------------------------------------------
- ??scale:
- test [flags],SHAPE_SCALING ; are we scaling this shape.
- jz ??shadow ; if not then skip scale y value
- mov eax,[flags + edi]
- mov [ScaleX],eax
- mov eax,[flags + edi + 4]
- mov [ScaleY],eax
- add edi,8 ; next argument
- ;--------------------------------------------------------------------
- ; SHAPE_SHADOW: DWORD shadow_table[256]
- ;--------------------------------------------------------------------
- ??shadow:
- test [flags],SHAPE_SHADOW ; are we ghosting this shape
- jz short ??get_header ; if not then skip
- mov eax,[flags + edi]
- mov [ShadowingTable],eax ; save address of shadow table
- add edi,4 ; next argument
- ??get_header:
- ;====================================================================
- ; Get Shape header values
- ;====================================================================
- mov esi,[shape_ptr] ; prepare to read header
- movzx eax,[WORD PTR esi]
- mov [ShapeType],eax ; extract shape type
- movzx eax,[BYTE PTR esi + 2]
- mov [ShapeHeight],eax
- movzx eax,[WORD PTR esi + 3] ; extract shape height
- mov [ShapeWidth],eax
- movzx eax,[WORD PTR esi + 8] ; extract uncompressed data length
- mov [UncompDataLen],eax
- add esi,10 ; reposition index
- ;--------------------------------------------------------------------
- ; Now get NumColors, ColorTable address, & data pointer:
- ; <16-color shape:
- ; shape.Colortable[0] = # colors
- ; shape data is after that many colors
- ; 16-color shape:
- ; shape.Colortable[] contains colors
- ; shape data is after those colors
- ; default 256-color shape:
- ; shape data starts at shape.Colortable[0]
- ; Note: ColorTable is set only if flags & SHAPE_COLOR is 0; otherwise,
- ; the color table was passed in & we already have a pointer to it
- ;--------------------------------------------------------------------
- ;
- ;....................... <16-color shape: ...........................
- ;
- test [ShapeType],MAKESHAPE_VARIABLE
- jz ??check_16
- movzx eax,[BYTE PTR esi] ; read # colors
- mov [NumColors],eax ; save # colors
- inc esi
- test [flags],SHAPE_COLOR ; don't set ColorTable if
- jnz ??norm_get_data_addr ; it was passed in
- mov [ColorTable],esi ; save color table pointer
- ??norm_get_data_addr:
- add esi,[NumColors] ; skip past color data
- mov [ShapeData],esi ; set data address
- jmp ??setup_procs
- ;....................... 16-color shape: ............................
- ??check_16:
- test [ShapeType],MAKESHAPE_COMPACT
- jz ??256_get_data_addr
- mov [NumColors],16 ; save # colors
- test [flags],SHAPE_COLOR ; don't set ColorTable if
- jnz ??16_get_data_addr ; it was passed in
- mov [ColorTable],esi ; save color table pointer
- ??16_get_data_addr:
- add esi,[NumColors] ; skip past color data
- mov [ShapeData],esi ; set data address
- jmp ??setup_procs
- ;
- ;....................... 256-color shape: ...........................
- ;
- ??256_get_data_addr:
- mov [ShapeData],esi ; set data address
- ;====================================================================
- ; Set up the drawing procedure addresses
- ;====================================================================
- ;--------------------------------------------------------------------
- ; This code uses HORZ_REV, VERT_REV, & SCALING flags as an
- ; offset into the LSkipTable, RSkipTable, and DrawTable. These
- ; flags combined have values from 00h-07h, so each table must have
- ; at least 8 entries.
- ;--------------------------------------------------------------------
- ??setup_procs:
- mov ebx,[flags] ; load flags value
- and ebx,07h ; clip high bits
- add ebx,ebx ; mult by 4 to get DWORD offset
- add ebx,ebx
- mov eax,[LSkipTable + ebx] ; get table value
- mov [LSkipRout],eax ; store it in the function pointer
- mov eax,[RSkipTable + ebx] ; get table value
- mov [RSkipRout],eax ; store it in the function pointer
- mov eax,[DrawTable + ebx] ; get table value
- mov [DrawRout],eax ; store it in the function pointer
- ??compute_scalevals:
- ;====================================================================
- ; Now compute scaled width & height. If the shape scales down to 0
- ; either horizontally or vertically, exit.
- ;====================================================================
- test [flags],SHAPE_SCALING ; skip if no scaling
- jz ??no_scaling
- ;
- ;........................ scaled width: .............................
- ;
- mov eax,[ShapeWidth] ; get byte width
- mov ebx,[ScaleX] ; prepare for register mul
- mul ebx ; EDX:EAX = result
- shrd eax,edx,8 ; EAX = result rounded down
- or eax,eax
- jz ??exit ; exit if EAX is 0
- mov [ScaledWidth],eax ; save the scaled width
- ;
- ;........................ scaled height: ............................
- ;
- mov eax,[ShapeHeight] ; get byte height
- mov ebx,[ScaleY] ; prepare for register mul
- mul ebx ; EDX:EAX = result
- shrd eax,edx,8 ; EAX = result rounded down
- or eax,eax
- jz ??exit ; exit if EAX is 0
- mov [ScaledHeight],eax ; save the scaled height
- jmp ??handle_centering
- ;
- ;......................... no scaling: ..............................
- ;
- ??no_scaling:
- mov eax,[ShapeWidth]
- mov [ScaledWidth],eax ; pixel width = byte width
- mov eax,[ShapeHeight]
- mov [ScaledHeight],eax ; pixel height = byte height
- ;====================================================================
- ; Allow for SHAPE_CENTER by adjusting the draw_x & draw_y arguments:
- ; draw_x -= ScaledWidth / 2
- ; draw_y -= ScaledHeight / 2
- ;====================================================================
- ??handle_centering:
- ;
- ;........................ adjust draw_x .............................
- ;
- test [flags],SHAPE_CENTER ; skip if not centered
- jz ??handle_vp_rel
- mov eax,[draw_x] ; load in draw_x
- mov edx,[ScaledWidth] ; load in ScaledWidth
- shr edx,1 ; divide it by 2
- sub eax,edx ; subract it from eax
- mov [draw_x],eax ; store it back into draw_x
- ;
- ;........................ adjust draw_y .............................
- ;
- mov eax,[draw_y] ; load in draw_y
- mov edx,[ScaledHeight] ; load in ScaledHeight
- shr edx,1 ; divide it by 2
- sub eax,edx ; subract it from eax
- mov [draw_y],eax ; store it back into draw_y
- ;====================================================================
- ; Allow for SHAPE_VIEWPORT_REL by adjusting draw_x & draw_y by the
- ; viewport's coordinates
- ;====================================================================
- ??handle_vp_rel:
- test [flags],SHAPE_VIEWPORT_REL ; skip if not vp-relative
- jz ??compute_horz_clip
- mov eax,[viewport_x]
- add [draw_x],eax ; draw_x += viewport_x
- mov eax,[viewport_y]
- add [draw_y],eax ; draw_y += viewport_y
- ;====================================================================
- ; Now that we have the scaled size and adjusted x & y drawing
- ; coordinates, we can compute the clipped areas of the shape:
- ; LeftClipPixels = viewport_x - draw_x
- ; - if negative, set to 0
- ; RightClipPixels = (draw_x + ScaledWidth) -
- ; (viewport_x + viewport_width)
- ; - if negative, set to 0
- ;
- ; TopClipPixels = viewport_y - draw_y
- ; - if negative, set to 0
- ; BotClipPixels = (draw_y + ScaledHeight) -
- ; (viewport_y + viewport_height)
- ; - if negative, set to 0
- ;====================================================================
- ??compute_horz_clip:
- ;
- ;...................... left-clipped pixels .........................
- ;
- mov eax,[viewport_x]
- sub eax,[draw_x] ; EAX = viewport_x - draw_x
- jge ??set_left_clip
- mov eax,0 ; if EAX<0, set to 0
- ??set_left_clip:
- mov [LeftClipPixels],eax ; store # left-clipped pixels
- ;
- ;...................... right-clipped pixels ........................
- ;
- mov eax,[draw_x]
- add eax,[ScaledWidth] ; EAX = draw_x + ScaledWidth
- mov edx,[viewport_x]
- add edx,[viewport_width] ; EDX = viewport_x + viewport_width
- sub eax,edx
- jge ??set_right_clip
- mov eax,0 ; if EAX<0, set to 0
- ??set_right_clip:
- mov [RightClipPixels],eax ; store # right-clipped pixels
- ;
- ;...................... top-clipped pixels ..........................
- ;
- ??compute_vert_clip:
- mov eax,[viewport_y]
- sub eax,[draw_y] ; EAX = viewport_y - draw_y
- jge ??set_top_clip
- mov eax,0 ; if EAX<0, set to 0
- ??set_top_clip:
- mov [TopClipPixels],eax ; store # top-clipped pixels
- ;
- ;.................... bottom-clipped pixels .........................
- ;
- mov eax,[draw_y]
- add eax,[ScaledHeight] ; EAX = draw_y + ScaledHeight
- mov edx,[viewport_y]
- add edx,[viewport_height] ; EDX = viewport_y + viewport_height
- sub eax,edx
- jge ??set_bottom_clip
- mov eax,0 ; if EAX<0, set to 0
- ??set_bottom_clip:
- mov [BotClipPixels],eax ; store # bottom-clipped pixels
- ;====================================================================
- ; Now compute the number of pixels actually drawn, horizontally and
- ; vertically; exit if either is <= 0
- ;====================================================================
- ??compute_drawn_pixels:
- ;
- ;.................... pixel width of drawn area .....................
- ;
- mov eax,[ScaledWidth] ; get total width in pixels
- sub eax,[LeftClipPixels] ; subtract off left-clipped pixels
- sub eax,[RightClipPixels] ; subtract off right-clipped pixels
- jle ??exit ; exit if no horizontal pixels drawn
- mov [PixelWidth],eax ; store drawn pixel width
- ;
- ;.................... pixel height of drawn area ....................
- ;
- mov eax,[ScaledHeight] ; get total height in pixels
- sub eax,[TopClipPixels] ; subtract off top-clipped pixels
- sub eax,[BotClipPixels] ; subtract off bottom-clipped pixels
- jle ??exit ; exit if no horizontal pixels drawn
- mov [PixelHeight],eax ; store drawn pixel height
- ;====================================================================
- ; So, we're actually going to draw something; if (ShapeType &
- ; MAKESHAPE_NOCOMP == 0) decompress the shape data into _ShapeBuffer:
- ; LCW_Uncompress(ShapeData, _ShapeBuffer, UncompDataLen);
- ; shape.DataLength
- ; &_ShapeBuffer
- ; &(shape's data)
- ; - otherwise the shape data is already uncompressed
- ;====================================================================
- test [ShapeType],MAKESHAPE_NOCOMP
- jnz ??uncompressed
- mov eax,[UncompDataLen]
- push eax ; push arg 3
- mov eax,[_ShapeBuffer]
- push eax ; push arg 2
- mov eax,[ShapeData]
- push eax ; push arg 1
- call LCW_Uncompress ; call routine
- add esp,12 ; restore stack
- mov eax,[_ShapeBuffer]
- mov [ShapeData],eax
- jmp ??copy_flags
- ??uncompressed:
- ; mov eax,[ShapeData] ; set up pointer to shape data
- ; mov [_ShapeBuffer],eax
- ;--------------------------------------------------------------------
- ; Set the global Flags variable
- ;--------------------------------------------------------------------
- ??copy_flags:
- mov eax,[flags]
- mov [Flags],eax
- ;====================================================================
- ; Now compute the actual buffer offset where drawing (not skipping)
- ; will begin
- ;====================================================================
- ;--------------------------------------------------------------------
- ; First, compute the x & y offsets of the shape's clipped upper-left
- ; corner, relative to the viewport's upper-left corner:
- ; x-offset = draw_x + LeftClipPixels - viewport_x
- ; y-offset = draw_y + TopClipPixels - viewport_y
- ;--------------------------------------------------------------------
- mov ebx,[draw_x]
- add ebx,[LeftClipPixels]
- sub ebx,[viewport_x] ; EBX = viewport x-offset
- mov eax,[draw_y]
- add eax,[TopClipPixels]
- sub eax,[viewport_y] ; EAX = viewport y-offset
- ;--------------------------------------------------------------------
- ; Then, adjust the viewport offsets due to horizontal & vertical
- ; reversal:
- ; if HORZ_REV, x-offset += (PixelWidth - 1)
- ; if VERT_REV, y-offset += (PixelHeight - 1)
- ;--------------------------------------------------------------------
- ;
- ;................. Adjust for horizontal reversal ...................
- ;
- test [flags],SHAPE_HORZ_REV
- jz ??adjust_vert_offset
- add ebx,[PixelWidth]
- dec ebx ; EBX = true x-offset
- ;
- ;................ Swap LeftClip & RightClip pixels ..................
- ;
- mov edx,[LeftClipPixels] ; exchange left & right-clipped pixels
- xchg edx,[RightClipPixels]
- mov [LeftClipPixels],edx
- ;
- ;.................. Adjust for vertical reversal ....................
- ;
- ??adjust_vert_offset:
- test [flags],SHAPE_VERT_REV
- jz ??adjust_pointer
- add eax,[PixelHeight]
- dec eax ; EAX = true y-offset
- ;
- ;.................. Swap TopClip & BotClip pixels ...................
- ;
- mov edx,[TopClipPixels]
- xchg edx,[BotClipPixels]
- mov [TopClipPixels],edx
- ;--------------------------------------------------------------------
- ; Now, adjust the starting position pointer:
- ;--------------------------------------------------------------------
- ??adjust_pointer: ;!!!!!!! convert to register mul for speed !!!!!!!!
- add ebx,[viewport_ptr] ; add initial ptr to x-offset
- mul [viewport_yadd] ; convert y-offset (EAX) to bytes
- add ebx,eax ; add those bytes in
- mov [StartDraw],ebx ; store the starting pointer
- ;--------------------------------------------------------------------
- ; Finally, if VERT_REV, negate yadd to move up not down:
- ;--------------------------------------------------------------------
- test [flags],SHAPE_VERT_REV
- jz ??init_xtotal
- neg [viewport_yadd] ; move up, not down
- ;====================================================================
- ; Initialize the horizontal scale accumulation value:
- ; If there are any left-clipped pixels, the scale accumulator will
- ; have to be initialized with the value it >would< have by stepping
- ; over that many pixels. This initial value can be computed by
- ; dividing the # of left-clipped pixels by the x-scale value itself,
- ; picking off the remainder from this division & negating it. This
- ; sets the low byte of the remainder to the correct accumulation
- ; value (the high bytes will be garbage).
- ; (The alternative to this approach would be to multiply the
- ; scale factor by the # clipped bytes, which is the result of the
- ; division; however, negating the remainder is much faster than
- ; the multiply would be.)
- ;====================================================================
- ??init_xtotal:
- mov edx,0 ; prepare for divide
- mov eax,[LeftClipPixels] ; get # left-clipped pixels
- shl eax,8 ; multiply by 100h
- mov ebx,[ScaleX] ; load ScaleX value
- div bx ; 16-bit div: AX = rslt, DX = rem
- mov [LeftClipBytes],eax ; save # left-clipped bytes
- neg edx ; generate roundoff bits
- and edx,0Fh ; only save low byte
- mov [XTotalInit],edx ; save initial roundoff value
- ;====================================================================
- ; Initialize drawing variables:
- ;====================================================================
- mov esi,[ShapeData] ; ESI = shape buffer starting point
- mov edi,[StartDraw] ; EDI = drawing address
- mov [YTotal],0 ; initialize accumulated scale
- ;====================================================================
- ; Clip the top-clipped lines. The object here is to set ESI to the
- ; first drawable line in the _ShapeBuffer, and YTotal to:
- ; high byte = # times to draw that line,
- ; low byte = roundoff bits
- ;
- ; - Initialize values (ESI, HeightCount, YTotal)
- ; - Skip loop if no top lines to clip
- ; - Loop:
- ; - save this line's byte position in _ShapeBuffer, in case we
- ; overrun
- ; - call RSkipRout with ECX set to # bytes to skip (one row)
- ; - accumulate ScaleY into YTotal
- ; - if high byte is non-zero, there are that many drawn lines:
- ; - decrement HeightCount by that many lines
- ; - clear the high byte in YTotal, but keep the roundoff bits
- ; - if HeightCount > 0, loop again to clip more lines
- ; - if HeightCount is 0, start drawing:
- ; - ESI points to first non-clipped line in _ShapeBuffer
- ; - YTotal contains 0 in high byte, roundoff bits in low byte
- ; - otherwise, we've clipped too many lines:
- ; - put ESI back to the line we just clipped
- ; - set high byte of YTotal to # lines overrun
- ; - subtract ScaleY from YTotal, to set it up for drawing loop
- ;====================================================================
- ;
- ;..................... skip if nothing to clip ......................
- ;
- mov eax,[TopClipPixels]
- cmp eax,0 ; see if any top-clipped pixels
- jz ??draw_loop ; if not, skip this
- mov [HeightCount],eax ; save off # lines to clip
- ??clip_y_loop:
- ;
- ;...................... skip this row of bytes ......................
- ;
- mov [LineStart],esi ; save this line's byte position
- mov ecx,[ShapeWidth] ; set up ECX for RSkipRout
- call [RSkipRout] ; skip 'ShapeWidth' bytes
- ;
- ;............... see if this row would have been drawn ..............
- ;
- mov eax,[ScaleY]
- add [YTotal],eax ; accumulate scale factor
- test [YTotal],0FF00h ; check to see if we draw the line
- jz ??clip_y_loop ; if not loop again
- ;
- ;...................... decrement HeightCount .......................
- ;
- mov eax,0 ; clear EAX
- xchg al,[BYTE PTR YTotal+1] ; get # lines, clear it in YTotal
- sub [HeightCount],eax ; subtract # drawn lines from HtCt
- jg ??clip_y_loop ; if more lines remain, loop again
- jns ??draw_loop ; is exactly 0; we're done clipping
- ;
- ;....................... adjust for overrun .........................
- ;
- mov esi,[LineStart] ; point ESI back to this line
- mov eax,[HeightCount]
- neg eax ; EAX = # lines overrun
- shl eax,8 ; multiply by 100h
- add eax,[YTotal] ; add in roundoff bits
- sub eax,[ScaleY] ; adjust down by y-scale
- mov [YTotal],eax ; store in YTotal
- ;====================================================================
- ; The drawing loop (at long last!):
- ; - Accumulate YTotal; if high byte is 0, skip this row of bytes &
- ; loop again
- ; - Skip left-clipped pixels:
- ; - If we've skipped all the bytes on the line, just go to the
- ; next line
- ; - Draw middle pixels:
- ; - Add the shape's pixel width to ECX (which could be negative
- ; if we left-skipped into the drawable area)
- ; - If ECX is still 0, there are no pixels to draw
- ; - Otherwise, leave ECX as is & draw the pixels
- ; - Skip right-clipped pixels:
- ; - Add # right-clipped pixels to ECX (which could be negative if
- ; the draw routine uncompressed 0's into the right-clipped
- ; region)
- ; - if ECX > 0, skip the remaining bytes
- ; - Go to the next line:
- ; - point EDI to the start of the next line in the viewport
- ; - decrement the height counter, exit if it's 0
- ; - decrement YTotal's high byte
- ; - if it's 0, go to the loop top
- ; - otherwise, reset ESI to this line's start & redraw the line,
- ; starting at left-clipped pixels
- ; (NOTE: why not start drawing at middle pixels??????????)
- ;====================================================================
- ??draw_loop:
- ;
- ;................... accumulate YTotal & test it ....................
- ;
- mov eax,[ScaleY] ; get y scaling factor
- add [YTotal],eax ; accumulate YTotal
- test [YTotal],0FF00h ; see if we need to draw anything
- jnz ??draw_line ; draw this line
- ;
- ;......................... skip this line ...........................
- ;
- mov ecx,[ShapeWidth] ; load shape's width in bytes
- call [RSkipRout] ; skip this row & loop again
- jmp ??draw_loop
- ;
- ;--------------------- start drawing this line ----------------------
- ;
- ??draw_line:
- mov [LineStart],esi ; save current byte position
- ;....................................................................
- ; Skip left-clipped pixels:
- ; - initialize [WidthCount] to total shape width in bytes
- ; - set ECX to # >bytes< to clip
- ; When LSkipRout returns:
- ; - ECX will contain # >pixels< overrun
- ; - EDX will contain the XTotal init value
- ; - [WidthCount] will be decremented by total bytes skipped
- ;....................................................................
- ??draw_left:
- mov eax,[ShapeWidth] ; load shape width
- mov [WidthCount],eax ; set up for LSkipRout
- mov ecx,[LeftClipBytes] ; bytes, not pixels!
- call [LSkipRout] ; skip the bytes
- cmp [WidthCount],0
- jz ??next_line ; The whole line was 0's
- ;....................................................................
- ; Draw middle pixels:
- ; - add PixelWidth to ECX (which may be negative)
- ; - if ECX is 0, don't bother drawing
- ; When DrawRout returns:
- ; - ECX will contain # >pixels< overrun
- ; - [WidthCount] will be decremented by # bytes drawn
- ;....................................................................
- ??draw_middle:
- add ecx,[PixelWidth] ; since ECX could overrun, add width
- jle ??draw_right ; if ECX<=0, no middle pixels to draw
- call [DrawRout] ; draw the pixels
- ;
- ;................... skip past right-clipped pixels .................
- ;
- ??draw_right:
- mov ecx,[WidthCount] ; ECX = remaining # bytes
- jecxz ??next_line ; don't bother if no bytes remain
- call [RSkipRout] ; skip right-clipped bytes
- ;
- ;----------------------- go to the next line ------------------------
- ;
- ??next_line:
- ;
- ;................. adjust EDI to start of next line .................
- ;
- mov eax,[viewport_yadd] ; get yadd
- add [StartDraw],eax ; add it to this line's position
- mov edi,[StartDraw] ; EDI = next line
- ;
- ;................. decrement our pixel row counter ..................
- ;
- dec [PixelHeight] ; count down a line
- jz ??exit ; we're done!
- ;
- ;.................. decrement YTotal's high byte ....................
- ;
- dec [BYTE PTR YTotal + 1] ; decrement high byte
- jz ??draw_loop ; draw next line if 0
- ;
- ;....................... re-draw this line ..........................
- ;
- mov esi,[LineStart] ; reset to this line's start
- jmp ??draw_left ; redraw this line
- ??exit:
- ret
- ENDP Draw_Shape
- ;***************************************************************************
- ;* Not_Supported -- Replacement function for Draw_Shape routines not used. *
- ;* *
- ;* INPUT: *
- ;* none. *
- ;* *
- ;* OUTPUT: *
- ;* none. *
- ;* *
- ;* WARNINGS: *
- ;* none. *
- ;* *
- ;* HISTORY: *
- ;* 08/24/1993 SKB : Created. *
- ;*=========================================================================*
- PROC Not_Supported NOLANGUAGE NEAR
- ret
- ENDP Not_Supported
- END
- ;************************** End of drawshp.asm *****************************
|