Metropoli BBS
VIEWER: plasma.asm MODE: TEXT (ASCII)
;=============================================================================
; plasma.asm - Plasma Clouds fractal calculation routine.
;                                                     File created: 9-26-93
; Copyright (c) 1993, Carlos Hasan                   Last modified: 9-26-93
;
; Description:
;  This file implements the plasma clouds routine using a recursive algorithm
;  optimized for use with VGA 320x200x256 graphics mode. There must be enough
;  stack space for this routine.
;
; Portability:
;  Requires Turbo Assembler 3.2 or better to be assembler.
;  Dependent on the IBM PC 286 or later microprocessor.
;=============================================================================

                .model  small,pascal
                .286

                global  DrawPlasma:proc

;===================== Plasma equates ========================================

MAXWIDTH        equ     320                     ; virtual screen dimensions.
MAXHEIGHT       equ     200
MAXCOLOR        equ     255                     ; max colors for plasma.
SHIFTVALUE      equ     2                       ; granularity shift.

;====================== Plasma data ==========================================

                .data

RandSeed        dw      ?                       ; random generator seed.

;====================== Plasma routines ======================================

                .code

;-----------------------------------------------------------------------------
; Random - Returns a random number of 16 bits, modified version of the
;  ripped System unit random routine of the Borland Pascal 7.0.
; Out:
;  AX - random value.
; Modified:
;  AX, DX, Flags.
;-----------------------------------------------------------------------------

Random          proc near

                mov     ax,[RandSeed]
                mov     dx,8405h
                mul     dx
                inc     ax
                mov     [RandSeed],ax
                ret

Random          endp


;-----------------------------------------------------------------------------
; GetPixel - get the pixel color at specified location.
; In:
;   ES    - virtual screen segment.
;   (X,Y) - pixel location.
; Out:
;   AL    - pixel color value.
; Modified:
;   BX, Flags.
;-----------------------------------------------------------------------------

GetPixel        macro   X,Y

                mov     bx,Y
                imul    bx,MAXWIDTH
                add     bx,X
                mov     al,es:[bx]

                endm

;-----------------------------------------------------------------------------
; PutPixel - put the pixel color at specified location.
; In:
;   ES    - virtual screen segment.
;   (X,Y) - pixel location.
;   AL    - pixel value.
; Modified:
;   BX, Flags.
;-----------------------------------------------------------------------------

PutPixel        macro   X,Y

                mov     bx,Y
                imul    bx,MAXWIDTH
                add     bx,X
                mov     es:[bx],al

                endm


;----------------------------------------------------------------------------
; Adjust - adjust a new pixel value using two neighboring pixels.
; In:
;  (XA,YA) - first near pixel.
;  (XB,YB) - second near pixel.
;  (X,Y)   - new pixel.
; Out:
;  AX      - new pixel color value.
; Modified:
;  AX, BX, DX, SI, DI, Flags.
;----------------------------------------------------------------------------

Adjust          proc near XA:word,YA:word,X:word,Y:word,XB:word,YB:word

                mov     si,[X]                  ; if already painted
                mov     di,[Y]                  ; the pixel, use this
                xor     ax,ax                   ; one instead of new
                GetPixel si,di                  ; calculation.
                test    ax,ax
                jne     AdjExit

                call    Random                  ; get a random variation
                mov     bx,[XB]                 ; dependent of the pixels
                sub     bx,[XA]                 ; distance and granularity
                add     bx,[YB]                 ; shift factor.
                sub     bx,[YA]
                shl     bx,SHIFTVALUE
                imul    bx
                xor     ax,ax                   ; adds the average of the
                GetPixel [XA],[YA]              ; near pixels colors.
                add     dx,ax
                GetPixel [XB],[YB]
                add     ax,dx
                shr     ax,1
                cmp     ax,1                    ; check if new color is
                jge     ColorUp                 ; in the right range.
                mov     ax,1
ColorUp:        cmp     ax,MAXCOLOR
                jle     ColorDn
                mov     ax,MAXCOLOR
ColorDn:        PutPixel si,di                  ; paint pixel color.
AdjExit:        ret

Adjust          endp


;-----------------------------------------------------------------------------
; SubDivide - main plasma routine that divides a region recursively.
; In:
;   (X1,Y1,X2,Y2) - screen plasma region.
; Modified:
;   AX, BX, CX, DX, Flags.
;-----------------------------------------------------------------------------

SubDivide       proc near X1:word,Y1:word,X2:word,Y2:word
                local   X:word,Y:word

                mov     ax,[X2]                 ; test if this region
                sub     ax,[X1]                 ; needs a sub-division.
                cmp     ax,2
                jge     SubDivCont
                mov     ax,[Y2]
                sub     ax,[Y1]
                cmp     ax,2
                jge     SubDivCont
                jmp     SubDivExit

SubDivCont:     mov     ax,[X1]                 ; get the center position
                add     ax,[X2]                 ; of the region.
                rcr     ax,1
                mov     [X],ax
                mov     ax,[Y1]
                add     ax,[Y2]
                rcr     ax,1
                mov     [Y],ax

                ; get the sum of the neighboring four pixel colors.
                xor     cx,cx
                call    Adjust, [X1],[Y1], [X],[Y1], [X2],[Y1]
                add     cx,ax
                call    Adjust, [X2],[Y1], [X2],[Y], [X2],[Y2]
                add     cx,ax
                call    Adjust, [X1],[Y2], [X],[Y2], [X2],[Y2]
                add     cx,ax
                call    Adjust, [X1],[Y1], [X1],[Y], [X1],[Y2]
                add     cx,ax

                mov     si,[X]                  ; test if the center pixel
                mov     di,[Y]                  ; need to be calculated.
                GetPixel si,di
                test    al,al
                jne     SubDivNow
                mov     ax,cx                   ; yes, use the average of
                add     ax,2                    ; the neighboring pixels.
                shr     ax,2                    ; (don't allow color 0)
                PutPixel si,di

                ; sub-divides the new four regions.
SubDivNow:      call    SubDivide, [X1],[Y1], [X],[Y]
                call    SubDivide, [X],[Y1], [X2],[Y]
                call    SubDivide, [X],[Y], [X2],[Y2]
                call    SubDivide, [X1],[Y], [X],[Y2]

SubDivExit:     ret

SubDivide       endp

;-----------------------------------------------------------------------------
; DrawPlasma - Main routine to draw plasma into a virtual screen.
; In:
;   (X1,Y1,X2,Y2) - Virtual screen Window location.
;   Seed          - Initial random seed for the plasma generator.
;   ScreenSeg     - Virtual screen segment.
;-----------------------------------------------------------------------------

DrawPlasma      proc    XStart:word,YStart:word,XStop:word,YStop:word, \
                  Seed:word,ScreenSeg:word

                mov     ax,[ScreenSeg]          ; setup virtual screen
                mov     es,ax                   ; segment,

                mov     ax,[Seed]               ; and random calculation
                mov     [RandSeed],ax           ; seed.

                call    Random                  ; set window corner pixels.
                or      al,1
                PutPixel [XStart],[YStart]

                call    Random
                or      al,1
                PutPixel [XStop],[YStart]

                call    Random
                or      al,1
                PutPixel [XStart],[YStop]

                call    Random
                or      al,1
                PutPixel [XStop],[YStop]

                call    SubDivide, [XStart],[YStart], [XStop],[YStop]
                ret

DrawPlasma      endp

                end
[ RETURN TO DIRECTORY ]