Path: pdxgate!usenet.ee.pdx.edu!reed!ogicse!decwrl!wupost!howland.reston.ans.net!bogus.sura.net!news-feed-1.peachnet.edu!umn.edu!gaia.ucs.orst.edu!ucs.orst.edu!ketrenoj
From: ketrenoj@ucs.orst.edu (Lord Logics)
Newsgroups: comp.sys.ibm.pc.demos
Subject: Scaling code in ASM . . .
Message-ID: <1q568m$hdv@gaia.ucs.orst.edu>
Date: 10 Apr 93 01:01:10 GMT
Organization: University Computing Services - OSU
Lines: 97
NNTP-Posting-Host: ucs.orst.edu

Fellow netters, coders, and other people . . .
 
Finally a decent news group for exchanging source code . . .  here's
my first contribution.  I wrote the code in the beginning of last 
summer.  It was the first code I wrote that implemented the VGA (I had 
just purchased VGA)  Anyway, this is the fastest method I could come up 
with for scaling an image.  If there is a faster way, please post, or if 
you make any optimizations to this routine, please post them as well.
 
Sorry if it is hard to follow, and if the comments are confusing.
 
Oh yeah, I don't know what the normal message limit is, so I'll split 
this up into 100 line increments.  Should be a total of 3 posts.
 
NOTE:  I haven't tested this routine in quite a while, and I can't 
remember if I had made any changes since I last used it.  If it doesn't 
work, let me know and I'll work on it.
 
 
James
-=[ Lord Logics ]=-
 
ketrenoj@ucs.orst.edu
 
 
 
;----------
 
.model huge,c
.data
 
        X_SIZE          dw      0
        Y_SIZE          dw      0
        X_SKIP          dw      0
 
.code
;*************************************************************************
;** PROC: pixelate()
;** PURP: To put an image onto the screen from VGA memory w/ pitching
;** USAG: pixelate(char *buffer,int x,int y,int ratio);
;**       Ratio is a word.  The value is in a ratio of 256.  So,
;**       the ratio of 520 would result in 49% of the original size.
;**       (In other words, 256/Ratio = New Size)
;**
;**       Buffer is broken down as follows:
;**       X Size (2), Y Size (2), then the image. 
;**
;**       NOTE:  No clipping is done for this, and it is currently
;**              only written to support chained mode.  I am rewriting
;**              it to perform clipping and support for unchained video
;**              modes.  Questions or comments email:
;**            
;**              ketrenoj@ucs.orst.edu
;**              -=[ Lord Logics ]=-      
;**       Group: None.  Want me?  Contact me . . .
;**
;*************************************************************************
pixelate        proc far
        push    bp
        mov     bp,sp
        push    es
        push    ds
        push    si
        push    di
 
        cld
 
        mov     ax,@data
        mov     ds,ax
 
        mov     di,[bp+8]       ; Set ES:[DI] to point to the buffer . . .
        mov     es,di           ; :
        mov     di,[bp+6]       ; :
 
        mov     dx,es:[di]      ; X_SIZE is stored in DX
        mov     cx,es:[di+2]    ; Y_SIZE is stored in CX
 
        mov     ax,[bp+14]      ; We will now do some adjustemnts via ratio
        push    dx              ; Set up the ratio factor to adjust the
        push    ax              ; : X_SIZE and Y_SIZE, and X and Y POS.
        mul     dx              ; :
        mov     bx,0100h        ; :
        div     bx              ; :
        mov     X_SIZE,ax       ; : Newly adjusted X_SIZE (after pitching)
        pop     ax              ; :
        mul     cx              ; :
        div     bx              ; :
        mov     Y_SIZE,ax       ; : Newly adjusted Y_SIZE (after pitching)
        pop     dx              ; :
 
;** Now check to make sure that there is indeed something to display . . .
        cmp     X_SIZE,0        ; Check to see if there is still an image.
        jz      px_d            ; :
        cmp     Y_SIZE,0        ; :
        jz      px_d            ; :

; Continued in next post . . .

Path: pdxgate!usenet.ee.pdx.edu!reed!ogicse!flop.ENGR.ORST.EDU!gaia.ucs.orst.edu!ucs.orst.edu!ketrenoj
From: ketrenoj@ucs.orst.edu (Lord Logics)
Newsgroups: comp.sys.ibm.pc.demos
Subject: Scaling code in ASM [2/3]
Message-ID: <1q56d9$ho7@gaia.ucs.orst.edu>
Date: 10 Apr 93 01:03:37 GMT
References: <1q568m$hdv@gaia.ucs.orst.edu>
Organization: University Computing Services - OSU
Lines: 87
NNTP-Posting-Host: ucs.orst.edu

; Continued from last post . . .
 
;** Now we will figure out how much the X and Y POS will be changed . . .
;** On entry:
;** AX - Nothing
;** BX - Nothing
;** CX - Y_SIZE (no pitching)
;** DX - X_SIZE (no pitching)
;** ES:[DI] - Image Buffer
;** DS:[SI] - Nothing
px_sx:  sub     dx,X_SIZE       ; Set up the X_SIZE variance . . .
        jge     px_xn           ; : Variance = 1/2 the size difference . . .
        neg     dx              ; :
        shr     dx,1            ; :
        neg     dx              ; :
        jmp     px_sy           ; :
px_xn:  shr     dx,1            ; :
px_sy:  sub     cx,Y_SIZE       ; Set up the Y_SIZE variance . . .
        jge     px_yn           ; :
        neg     cx              ; :
        shr     cx,1            ; :
        neg     cx              ; :
        jmp     px_si           ; :
px_yn:  shr     cx,1            ; :
 
px_si:  xor     bx,bx           ; Clear initial DI displacement.
        push    dx
        mov     ax,[bp+12]      ; Set up the starting point and check
        add     ax,cx           ; : to make sure that the image will fit
        cmp     ax,200          ; : within our bounds (ie, the screen).
        jge     px_d            ; :
        cmp     ax,0            ; :
        jge     px_s1           ; :
        push    ax              ; :
        neg     ax              ; :
        sub     Y_SIZE,ax       ; :             THE FOLLOWING MAY CAUSE
        jle     px_ddx          ; :             PROBLEMS DURING CLIPPING.
        mov     dx,es:[di]      ; : Set DX to X_SIZE (no pitching)
        push    ax              ; :
        mul     dx              ; :
        mov     bx,ax           ; : BX stores DI adjustment . . .
        mov     dx,320          ; :
        pop     ax              ; :
        mul     dx              ; :
        mov     si,ax           ; :
        pop     ax              ; :
        jmp     px_s2           ; :
 
;**
;** Exit the procedure . . .
;**
px_ddx: pop     dx
px_dax: pop     ax
px_d:   pop     di
        pop     si
        pop     ds
        pop     es
        pop     bp
        ret
 
px_s1:  mov     dx,320          ; Adjust SI for proper positioning.
        mul     dx              ; :
        mov     si,ax           ; :
 
px_s2:  pop     dx              ; Now do the X Adjusting . . .
        mov     ax,[bp+10]      ; Set up the starting point and check
        add     ax,dx           ; : to make sure that the image will fit
        cmp     ax,320          ; : within our bounds (ie, the screen).
        jge     px_d            ; :
        cmp     ax,0            ; :
        jge     px_s3           ; :
        neg     ax              ; :
        sub     X_SIZE,ax       ; :
        jle     px_d            ; :
        add     bx,ax           ; :
        jmp     px_s4           ; :
 
px_s3:  add     si,ax           ; Set up screen position adjustment
px_s4:  mov     cx,bx
        mov     bx,es:[di]
        add     di,cx
        add     di,4
        mov     cx,Y_SIZE
        mov     dx,X_SIZE
        jmp     px_pixel

; Continued in next post . . .

Path: pdxgate!usenet.ee.pdx.edu!reed!ogicse!flop.ENGR.ORST.EDU!gaia.ucs.orst.edu!ucs.orst.edu!ketrenoj
From: ketrenoj@ucs.orst.edu (Lord Logics)
Newsgroups: comp.sys.ibm.pc.demos
Subject: Scaling code in ASM [3/3]
Message-ID: <1q56ii$hrj@gaia.ucs.orst.edu>
Date: 10 Apr 93 01:06:26 GMT
References: <1q568m$hdv@gaia.ucs.orst.edu>
Organization: University Computing Services - OSU
Lines: 87
NNTP-Posting-Host: ucs.orst.edu

; Continued from last post . . .
 
;**
;** Display the image as quick as possible.
;**
;** On entry:
;** ES:[DI] Points to image buffer
;** DS:[SI] Points to screen memory location (start point)
;** AX - nothing important
;** BX - X_SIZE w/out any pitching.  This is used to add to the memory
;**      buffer for each line displayed.
;** CX - Y_COUNT size.  The number of Y_LINES to display
;** DX - X_COUNT size.  The number of X_LINES to display
;**
px_pixel:
        ;** First we must set up our ratio skipping . . .
        push    dx              ; Save X_COUNT
        push    bx              ; Save X_SIZE
        mov     bx,[bp+14]      ; Set skipping bytes . . .
        xor     dx,dx           ; :
        mov     ax,0FFFFh       ; :
        or      bx,bx           ; :
        jz      px_pd           ; :
        div     bx              ; :
        jmp     px_pf           ; :
px_pd:  mov     ax,0100h        ; :
px_pf:  mov     [bp+14],ax      ; :
        pop     bx              ; Restore X_SIZE
        pop     dx              ; Restore X_COUNT
 
 
        ;** Now we must set up our starting points . . .
        mov     ax,es           ; Set DS:[SI] to our image,
        mov     ds,ax           ; : ES:[DI] to the screen position,
        mov     ax,0A000h       ; : BP to point to the ratio skip,
        mov     es,ax           ; : and AX to the skip, roll over . . .
        xchg    si,di           ; :
        add     bp,14           ; :
        mov     al,[bp+1]       ; :
        xor     ah,ah           ; :
        mov     [bp-2],ah       ; :
 
        ;** Now, actually display the image via to for/next loops . . .
pxq_y:  push    cx              ; Save the Y_COUNT
        push    ax              ; Save the Whole Adjustment
        push    bx              ; Save the X_SIZE (no pitching)
        push    dx              ; Save the X_COUNT
        push    si              ; Save the start of line position
 
        ;** Now we will loop through the X_LINE, first setting up the
        ;** : values needed internally though . . .
        mov     cx,dx           ; Set CX to X_COUNT
        mov     dl,[bp]         ; Set DL to Ratio
        xor     dh,dh           ; Clear the Spill Over
 
pxq_x:  movsb                   ; Move one byte
        dec     si              ; : Fix the SI from being incremented.
        add     dh,dl           ; Do pitching . . .
        adc     si,ax           ; :
        loop    pxq_x           ; Do the entire X_LINE
 
        ;** Now we will adjust for the next X_LINE along the Y_LINE . . .
        pop     si              ; Restore start of line position.
        pop     bx              ; Adjust the dest screen position . . .
        add     di,320          ; :
        sub     di,bx           ; :
 
        add     [bp-2],dl       ; Do the pitching . . .
        adc     ax,0            ; :
        mov     dx,ax           ; :
        pop     ax              ; : Restore AX to the X_SIZE
        mov     cx,bx           ; : Set CX to X_COUNT
        mov     bx,ax           ; : Set BX to X_SIZE
        mul     dx              ; :
        add     si,ax           ; :
        pop     ax              ; : Restore Whole Adjustment
        mov     dx,cx           ; : Set DX to X_COUNT
        pop     cx              ; Restore Y_COUNT
        loop    pxq_y           ; Do the entire Y_LINE.
        jmp     px_d            ; Exit the PIXELATE routine.
pixelate        endp            ; END OF PIXELATE
        end


; That's it.  It was written using MASM (don't know what version) but i don't
; think it uses any special pseudo ops from that, so it should work on TASM.
; 

Path: pdxgate!usenet.ee.pdx.edu!reed!ogicse!emory!news-feed-1.peachnet.edu!bogus.sura.net!howland.reston.ans.net!ux1.cso.uiuc.edu!news.cso.uiuc.edu!uxa.cso.uiuc.edu!jas37876
From: jas37876@uxa.cso.uiuc.edu (John A. Slagel)
Newsgroups: comp.sys.ibm.pc.demos
Subject: ModeX Bitmap Scaling Code...
Message-ID: <C58vGz.6Ev@news.cso.uiuc.edu>
Date: 10 Apr 93 01:43:47 GMT
Sender: usenet@news.cso.uiuc.edu (Net Noise owner)
Organization: University of Illinois at Urbana
Lines: 260


    Well, seeing how someone posted code to do scaling, here's my
    equivalent code for ModeX.  It requires an input bitmap of
    128x128 and scales up or down, with clipping, and the clipping
    only slows the display down by a constant amount no matter how
    much is clipped.  This only changes the pixel plane once for
    every column, so it is very fast for a ModeX routine.  

    I'm posting this in hopes that people unselfishly post some
    of there own code... Anyway, enjoy.   

    Oh yeah, erase the .sig at the end.

;=============================================================================
; XSTRETCHBMP By John A. Slagel,  jas37876@uxa.cso.uiuc.edu
; Feel free to use this any way you want.  Let me know if you find any
; bugs or optimizations, and I would be interested in seeing any final
; projects that use this. Thanks.
;
; This routine stretches (or shrinks) a 128x128 bitmap in VGA ModeX.
;   o Color Indices of 255 are "invisible" or "masked" -- They don't draw.
;   o Only changes the bitplane 1 time per column, so it is fairly fast.
;   o Can only be used in 320x??? modes.
;   o Requires a 128x128 bitmap.
;   o Will only stretch proportionally.
;   o Can stretch from 2 up to very large stretching.
;   o Clips according to ClipLt, ClipRt, ClipTp, ClipBt, which should be
;     declared in your C routine in another module. You also need to have
;     the ModeXseg variable declared elsewhere. Normally A000, A800, etc..
;   o Clipping only takes a constant time when it is neccessary.
;   o Requires a 386 processor
;   o Requires MASM 5.1
;   o C-callable as:
;       void XSTRETCHBMP( int x, int y, int w, BYTE  *Bitmap );
;            x,y = Screen Position
;            w   = Width to stretch it on the screen
;            Bitmap = Pointer to 128x128 byte array of pixel data 
;       Needs extern variables,ClipLt, ClipRt, ClipTp, ClipBt, ModeXseg
;============================================================================
.MODEL LARGE, C
.386

.DATA
SC_INDEX1       EQU 03C4h
SC_INDEX2       EQU 03C5h
MAP_MASK        EQU 2
INVISIBLE_COLOR EQU 255

extrn ClipTp:word
extrn ClipLt:word
extrn ClipRt:word
extrn ClipBt:word
extrn ModeXseg:word

.CODE

XSTRETCHBMP PROC FAR USES DI SI, DestXStart:WORD, DestYStart:WORD, DestSize:WORD, Bitmap:FAR PTR
LOCAL DestHeight:WORD, DecisionY:WORD, DestWidth:WORD,  DecisionX:WORD, DestSize2:WORD, Doff:WORD, Soff:WORD

        mov     DestHeight,0 
        mov     DecisionY, 0
        mov     DestWidth, 0
        mov     DecisionX, 0
        mov     DestSize2, 0
        mov     Doff, 0
        mov     Soff, 0

        cmp     DestSize, 2
        jl      Done        ; If it is too small then exit 

        mov     ax, DestYStart
        cmp     ax, ClipBt
        jg      Done        ; If it is too far down then exit 

        add     ax, DestSize
        dec     ax
        cmp     ax, ClipTp
        jl      Done        ; If it is too far up then exit

        mov     ax, DestXStart
        cmp     ax, ClipRt
        jg      Done        ; If it is too far right then exit 

        add     ax, DestSize
        dec     ax 
        cmp     ax, ClipLt
        jl      Done            ; If it is too far left then exit

        mov     ax, DestSize
        mov     DestWidth,  ax  ; Initialize DestWidth=DestSize
        mov     DestHeight, ax  ; Initialize DestHeight=DestSize

        mov     Soff, 0         ; Point Soff to start of bitmap

        mov     DestSize2, ax
        shl     DestSize2, 1    ; Calculate DestSize*2 for later

        shl     ax, 1
        neg     ax
        mov     DecisionX, ax   ; DecisionX = -DestSize
        mov     DecisionY, ax   ; DecisionY = -DestSize

        movsx   eax, ClipTp
        movsx   ecx, DestYStart
        sub     eax, ecx        ; EAX = ClipTp-DestYStart
        jle     NoTopClip
        ;Clip off the top
        sub     DestHeight, ax  ; DestHeight -= (ClipTp-DestYStart)
        mov     ebx, eax        ; EBX = AmountClippedY
        xor     edx, edx        ; EDX = 0
        shl     eax, 7          ; EDX:EAX = AmountClippedY * 128
        movzx   ecx, DestSize
        div     ecx             ; EAX (SourceStartY) = EDX:EAX / DestSize 
        add     Soff, ax        ; Soff = SourceStartY (EAX) 
        shl     Soff, 7         ;                           * 128
        shl     ebx, 8          ; EBX = AmountClippedY * 256
        shl     ecx, 1          ; ECX = DestSize2
        mul     ecx             ; EDX:EAX = SourceStartY * DestSize2
        sub     ebx, eax
        add     DecisionY, bx
        mov     ax, ClipTp
        mov     DestYStart, ax

NoTopClip:  
        mov     ax, DestYStart
        add     ax, DestHeight
        dec     ax
        cmp     ax, ClipBt
        jle NoBottomClip  
        ; Clip off the bottom
        mov     ax, ClipBt
        sub     ax, DestYStart
        inc     ax
        mov     DestHeight, ax

NoBottomClip:   
        movsx   eax, ClipLt
        movsx   ecx, DestXStart
        sub     eax, ecx
        jle     NoLeftClip
        ;Clip off the left side
        sub     DestWidth, ax   ; DestWidth -= (ClipLT-DestXStart)
        mov     ebx, eax        ; EBX = AmountClippedX
        xor     edx, edx        ; EDX = 0
        shl     eax, 7          ; EDX:EAX = AmountClippedX * 128
        movzx   ecx, DestSize
        div     ecx             ; EAX (SourceStartX) = EDX:EAX / DestSize 
        add     Soff, ax        ; Soff += SourceStartX (EAX) 
        shl     ebx, 8          ; EBX = AmountClippedX * 256
        shl     ecx, 1          ; ECX = DestSize2
        mul     ecx             ; EDX:EAX = SourceStartX * DestSize2
        sub     ebx, eax
        add     DecisionX, bx
        mov     ax, ClipLt
        mov     DestXStart, ax
NoLeftClip:     
        mov     ax, DestXStart
        add     ax, DestWidth
        dec     ax
        cmp     ax, ClipRt
        jle NoClipRight 
        ; Clip off the right
        mov     ax, ClipRt
        sub     ax, DestXStart
        inc     ax
        mov     DestWidth, ax

        ;Calculate starting video address
NoClipRight:    
        mov     ax, ModeXseg 
        mov     gs, ax
        movsx   eax, DestYStart 
        lea     eax, [eax*2]
        lea     eax, [eax*8]
        lea     eax, [eax+eax*4]
        mov     bx, DestXStart
        mov     cx, bx
        shr     bx, 2
        add     ax, bx
        mov     Doff, ax    ; gS:Doff -> VGA memory

	mov     dx, SC_INDEX1
        mov     al, MAP_MASK
        out     dx, al
        inc     dx
        and     cx, 3
        mov     al, 11h
        shl     al, cl
	out     dx, al      ; Select the first plane
        
        lfs     si, Bitmap
        add     Soff, si
	mov     dx, DestSize2
ColumnLoop:     
        mov     di, Doff
        mov     si, Soff
        mov     bx, DecisionY
        mov     cx, DestHeight
        inc     cx

        jmp     NextPixel
RowLoop:        
        mov     gs:[di], ah
        add     di, 80
        add     bx, 256
	js      Visible
IncSourceY:     
        add     si, 128
	sub     bx, dx
        jns     IncSourceY
NextPixel:      
        mov     ah, fs:[si]
        cmp     ah, INVISIBLE_COLOR
        je      MaskedPixel
Visible:
        loop    RowLoop
DoneWithCol:    
        rol     al, 1
        adc     Doff, 0
	mov     dx, SC_INDEX2
	out     dx, al
	mov     dx, DestSize2
	add     DecisionX, 256
        js      NextCol
        mov     bx, DecisionX
IncSourceX: 
        inc     Soff
	sub     bx, dx
        jns     IncSourceX
        mov     DecisionX, bx
NextCol:        
        dec     DestWidth
        jnz     ColumnLoop
Done:           
        ret

MRowLoop:       
        add     di, 80
        add     bx, 256
        js      MaskedPixel
MSourceIncY:    
        add     si, 128
	sub     bx, dx
        jns     MSourceIncY
        mov     ah, fs:[si]
        cmp     ah, INVISIBLE_COLOR
        jne     Visible
MaskedPixel:    
        loop    MRowLoop
        jmp     DoneWithCol

XSTRETCHBMP     ENDP


END
-- 
-----------------------------------------------------------------------------
 John A. Slagel              "My old man used to tell me, before he left this
 j-slagel1@uiuc.edu           shitty world, never chase buses or women- you
 (217) 337-7930               always get left behind." -The Marlboro Man

