Previous | Table of Contents | Next

LISTING 52.9 L52-9.ASM

    ; 386-specific fixed point multiply and divide.
    ;
    ; C near-callable as: Fixedpoint FixedMul(Fixedpoint M1, Fixedpoint M2);
    ;                 Fixedpoint FixedDiv(Fixedpoint Dividend, Fixedpoint Divisor);
    ;
    ; Tested with TASM
    ;
            .model small
            .386
            .code
            public  _FixedMul,_FixedDiv
    ; Multiplies two fixed-point values together.
    FMparms struc
            dw      2 dup(?)          ;return address & pushed BP
    M1      dd      ?
    M2      dd      ?
    FMparms ends
            align   2
    _FixedMul       proc    near
            push    bp
            mov     bp,sp
            mov     eax,[bp+M1]
            imul    dword ptr [bp+M2] ;multiply
            add     eax,8000h         ;round by adding 2^(-16)
            adc     edx,0             ;whole part of result is in DX
            shr     eax,16            ;put the fractional part in AX
            pop     bp
            ret
    _FixedMul       endp
    ; Divides one fixed-point value by another.
    FDparms struc
             dw     2 dup(?)          ;return address & pushed BP
    Dividend dd     ?
    Divisor  dd     ?
    FDparms ends
            align   2
    _FixedDiv       proc    near
            push    bp
            mov     bp,sp
            sub     cx,cx           ;assume positive result
            mov     eax,[bp+Dividend]
            and     eax,eax         ;positive dividend?
            jns     FDP1            ;yes
            inc     cx              ;mark it's a negative dividend
            neg     eax             ;make the dividend positive
    FDP1:   sub     edx,edx         ;make it a 64-bit dividend, then shift
                                    ; left 16 bits so that result will be in EAX
            rol     eax,16          ;put fractional part of dividend in
                                    ; high word of EAX
            mov     dx,ax           ;put whole part of dividend in DX
            sub     ax,ax           ;clear low word of EAX
            mov     ebx,dword ptr [bp+Divisor]
            and     ebx,ebx         ;positive divisor?
            jns     FDP2            ;yes
            dec     cx              ;mark it's a negative divisor
            neg     ebx             ;make divisor positive
    FDP2:   div     ebx             ;divide
            shr     ebx,1           ;divisor/2, minus 1 if the divisor is
            adc     ebx,0           ; even
            dec     ebx
            cmp     ebx,edx         ;set Carry if remainder is at least
            adc     eax,0           ; half as large as the divisor, then
                                    ; use that to round up if necessary
            and     cx,cx           ;should the result be made negative?
            jz      FDP3            ;no
            neg     eax             ;yes, negate it
    FDP3:   mov     edx,eax         ;return result in DX:AX; fractional
                                    ; part is already in AX
            shr     edx,16          ;whole part of result in DX
            pop     bp
            ret
    _FixedDiv       endp
            end

LISTING 52.10 POLYGON.H

    /* POLYGON.H: Header file for polygon-filling code, also includes
       a number of useful items for 3-D animation. */

    #define MAX_OBJECTS  100   /* max simultaneous # objects supported */
    #define MAX_POLY_LENGTH 4  /* four vertices is the max per poly */
    #define SCREEN_WIDTH 320
    #define SCREEN_HEIGHT 240
    #define PAGE0_START_OFFSET 0
    #define PAGE1_START_OFFSET (((long)SCREEN_HEIGHT*SCREEN_WIDTH)/4)
    #define NUM_CUBE_VERTS 8              /* # of vertices per cube */
    #define NUM_CUBE_FACES 6              /* # of faces per cube */
    /* Ratio: distance from viewpoint to projection plane / width of
       projection plane. Defines the width of the field of view. Lower
       absolute values = wider fields of view; higher values = narrower */
    #define PROJECTION_RATIO -2.0 /* negative because visible Z
                                     coordinates are negative */
    /* Draws the polygon described by the point list PointList in color
       Color with all vertices offset by (X,Y) */
    #define DRAW_POLYGON(PointList,NumPoints,Color,X,Y)          \
       Polygon.Length = NumPoints; Polygon.PointPtr = PointList; \
       FillConvexPolygon(&Polygon, Color, X, Y);
    #define INT_TO_FIXED(x) (((long)(int)x) << 16)
    #define DOUBLE_TO_FIXED(x) ((long) (x * 65536.0 + 0.5))

    typedef long Fixedpoint;
    typedef Fixedpoint Xform[3][4];
    /* Describes a single 2D point */
    typedef struct { int X; int Y; } Point;
    /* Describes a single 3D point in homogeneous coordinates; the W
       coordinate isn't present, though; assumed to be 1 and implied */
    typedef struct { Fixedpoint X, Y, Z; } Point3;
    typedef struct { int X; int Y; int Z; } IntPoint3;
    /* Describes a series of points (used to store a list of vertices that
       describe a polygon; each vertex is assumed to connect to the two
       adjacent vertices; last vertex is assumed to connect to first) */
    typedef struct { int Length; Point * PointPtr; } PointListHeader;
    /* Describes the beginning and ending X coordinates of a single
       horizontal line */
    typedef struct { int XStart; int XEnd; } HLine;
    /* Describes a Length-long series of horizontal lines, all assumed to
       be on contiguous scan lines starting at YStart and proceeding
       downward (used to describe a scan-converted polygon to the
       low-level hardware-dependent drawing code). */
    typedef struct { int Length; int YStart; HLine * HLinePtr;} HLineList;
    typedef struct { int Left, Top, Right, Bottom; } Rect;
    /* structure describing one face of an object (one polygon) */
    typedef struct { int * VertNums; int NumVerts; int Color; }  Face;
    typedef struct { double RotateX, RotateY, RotateZ; } RotateControl;
    typedef struct { Fixedpoint MoveX, MoveY, MoveZ, MinX, MinY, MinZ,
       MaxX, MaxY, MaxZ; } MoveControl;
    /* fields common to every object */
    #define BASE_OBJECT                                              \
       void (*DrawFunc)();     /* draws object */                    \
       void (*RecalcFunc)();   /* prepares object for drawing */     \
       void (*MoveFunc)();     /* moves object */                    \
       int RecalcXform;        /* 1 to indicate need to recalc */    \
       Rect EraseRect[2];      /* rectangle to erase in each page */
    /* basic object */
    typedef struct { BASE_OBJECT } Object;
    /* structure describing a polygon-based object */
    typedef struct {
       BASE_OBJECT
       int RDelayCount, RDelayCountBase; /* controls rotation speed */
       int MDelayCount, MDelayCountBase; /* controls movement speed */
       Xform XformToWorld;        /* transform from object->world space */
       Xform XformToView;         /* transform from object->view space */
       RotateControl Rotate;      /* controls rotation change over time */
       MoveControl Move;          /* controls object movement over time */
       int NumVerts;              /* # vertices in VertexList */
       Point3 * VertexList;       /* untransformed vertices */
       Point3 * XformedVertexList;   /* transformed into view space */
       Point3 * ProjectedVertexList; /* projected into screen space */
       Point * ScreenVertexList;     /* converted to screen coordinates */
       int NumFaces;              /* # of faces in object */
       Face * FaceList;           /* pointer to face info */
    } PObject;

    extern void XformVec(Xform, Fixedpoint *, Fixedpoint *);
    extern void ConcatXforms(Xform, Xform, Xform);
    extern int FillConvexPolygon(PointListHeader *, int, int, int);
    extern void Set320x240Mode(void);
    extern void ShowPage(unsigned int);
    extern void FillRectangleX(int, int, int, int, unsigned int, int);
    extern void XformAndProjectPObject(PObject *);
    extern void DrawPObject(PObject *);
    extern void AppendRotationX(Xform, double);
    extern void AppendRotationY(Xform, double);
    extern void AppendRotationZ(Xform, double);
    extern near Fixedpoint FixedMul(Fixedpoint, Fixedpoint);
    extern near Fixedpoint FixedDiv(Fixedpoint, Fixedpoint);
    extern void InitializeFixedPoint(void);
    extern void RotateAndMovePObject(PObject *);
    extern void InitializeCubes(void);
    extern int DisplayedPage, NonDisplayedPage, RecalcAllXforms;
    extern int NumObjects;
    extern Xform WorldViewXform;
    extern Object *ObjectList[];
    extern Point3 CubeVerts[];

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash